import backtrader as bt
import math
from .DbOprate import DbOprate

class SMACustom(bt.Indicator):
    """
    自定义SMA指标，模拟通达信的SMA(X,N,M)函数
    SMA(X,N,M) = (M*X + (N-M)*SMA(X,N,M)[1])/N
    """
    lines = ('sma',)
    params = (
        ('period', 2),
        ('weight', 1),
    )

    def __init__(self):
        pass

    def next(self):
        if len(self) == 1:  # 第一天
            self.lines.sma[0] = self.data[0]
        else:
            # SMA(X,N,M) = (M*X + (N-M)*SMA[1])/N
            m = self.params.weight
            n = self.params.period
            prev_sma = self.lines.sma[-1]
            current_data = self.data[0]
            self.lines.sma[0] = (m * current_data + (n - m) * prev_sma) / n

class XMASellStrategy(bt.Strategy):
    """
    X_7:=MA(CLOSE,1);
    X_8:=SMA(SMA(SMA(X_7,2,1),2,1),2,1);
    X_9:=MA(X_8,3);
    HL := X_8 >= X_9;
    LL := X_8 <= X_9;
    ZZD2 := LL AND REF(HL,1);
    S : ZZD2;
    """
    params = (
        ('print_debug', True),   
    )

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print(f'{dt.isoformat()}, {txt}')

    def __init__(self):
        self.data_close = self.datas[0].close
        
        # X_7:=MA(CLOSE,1);  收盘价的1日简单移动平均（实际上就是收盘价本身）
        self.x_7 = self.data_close  # MA(CLOSE,1)就是CLOSE本身
        
        # X_8:=SMA(SMA(SMA(X_7,2,1),2,1),2,1); 三层SMA嵌套
        # 第一层: SMA(X_7,2,1)
        self.sma_layer1 = SMACustom(self.x_7, period=2, weight=1)
        # 第二层: SMA(第一层结果,2,1)  
        self.sma_layer2 = SMACustom(self.sma_layer1, period=2, weight=1)
        # 第三层: SMA(第二层结果,2,1)
        self.x_8 = SMACustom(self.sma_layer2, period=2, weight=1)
        
        # X_9:=MA(X_8,3); X_8的3日简单移动平均
        self.x_9 = bt.indicators.SimpleMovingAverage(self.x_8, period=3)
        
        # HL := X_8 >= X_9;
        self.hl = self.x_8 >= self.x_9
        
        # LL := X_8 <= X_9;  
        self.ll = self.x_8 <= self.x_9

    def next(self):
        current_date = self.datas[0].datetime.date(0)
        current_price = self.data_close[0]

        # 确保有足够的数据来进行计算
        if (len(self.x_8) <= 0 or len(self.x_9) <= 0 or 
            len(self.hl) <= 0 or len(self.ll) <= 0):
            return
            
        # 检查是否所有指标都有有效值
        if (self.x_8[0] != self.x_8[0] or self.x_9[0] != self.x_9[0]):  # 检查NaN
            return

        # 确保有前一天数据
        if len(self.hl) < 2:
            return

        # 检查NaN值
        if (self.hl[0] != self.hl[0] or self.ll[0] != self.ll[0] or 
            self.hl[-1] != self.hl[-1]):  # 检查是否为NaN
            return

        # 调试打印
        if self.params.print_debug:
            x_7_value = self.x_7[0]
            x_8_value = self.x_8[0]  
            x_9_value = self.x_9[0]
            hl_value = int(self.hl[0])
            ll_value = int(self.ll[0])
            
            if self.hl[-1] == self.hl[-1]:  # 检查1日前HL是否为NaN
                prev_hl_value = int(self.hl[-1])
                zzd2_value = int(self.ll[0] and self.hl[-1])
                self.log(f'X_7: {x_7_value:.4f}, X_8: {x_8_value:.4f}, X_9: {x_9_value:.4f}, HL: {hl_value}, LL: {ll_value}, PREV_HL: {prev_hl_value}, ZZD2: {zzd2_value}')

        # 检查卖出信号条件：ZZD2 = LL AND REF(HL,1) (即 LL AND 1日前的HL)
        if (len(self.hl) >= 2 and self.hl[-1] == self.hl[-1] and  # 1日前HL有效
            self.ll[0] and self.hl[-1]):  # 当前LL且1日前HL
            
            self.log(f'*** XMA卖出信号触发 *** ZZD2 = LL AND REF(HL,1)')
            self.log(f'*** 当前价格: {current_price:.2f}, 持仓数量: {self.position.size}')
            
            # 存入数据库 - 卖出信号
            try:
                result = {
                    'strategy': 'XMASellStrategy',
                    'stock_code': self.datas[0]._name,
                    'op_act': 'sell_signal',
                    'op_price': float(current_price),
                    'op_num': int(self.position.size),
                    'op_comm': 0.0,
                    'op_dt': current_date.isoformat(),
                    'reason': 'XMA_Sell_Signal_ZZD2',
                    'x_7_value': float(self.x_7[0]),
                    'x_8_value': float(self.x_8[0]),
                    'x_9_value': float(self.x_9[0]),
                    'hl_value': int(self.hl[-1]),  # 1日前HL值
                    'll_value': int(self.ll[0]),   # 当前LL值
                }
                DbOprate.save_result_to_mysql(result)
                self.log(f'*** XMA卖出信号已存入数据库 ***')
            except Exception as e:
                self.log(f'*** 数据库存储失败 *** 错误: {str(e)}')

    def notify_order(self, order):
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'*** 买入订单完成 *** 价格: {order.executed.price:.2f}, 数量: {order.executed.size}')
            elif order.issell():
                self.log(f'*** 卖出订单完成 *** 价格: {order.executed.price:.2f}, 数量: {order.executed.size}')
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log(f'*** 订单失败 *** 状态: {order.Status[order.status]}')
